﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Diagnostics.Contracts;
using OpenWaves.ActivityFeed.Web.Controls;
using OpenWaves.ActivityFeed.Web.Modules;

namespace OpenWaves.ActivityFeed.Web
{
    public abstract class ActivityFeedBuilder
    {
        protected IActivityFeedService ActivityFeedService { get; private set; }
        protected IUpdateDtoBuilder UpdateDtoBuilder { get; private set; }

        public string SearchTerms { get; set; }
        public PaginationRequest PaginationRequest { get; set; }
        public IEnumerable<UserGroup> UserGroups { get; set; }
        public IEnumerable<Topic> TopicsFilter { get; set; }

        protected ActivityFeedBuilder(IActivityFeedService activityFeedService, IUpdateDtoBuilder updateDtoBuilder)
        {
            Contract.Requires<ArgumentNullException>(activityFeedService != null);
            Contract.Requires<ArgumentNullException>(updateDtoBuilder != null);

            this.ActivityFeedService = activityFeedService;
            this.UpdateDtoBuilder = updateDtoBuilder;
        }

        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        [SuppressMessage("Microsoft.Design", "CA1021:Consider a design that does not require that 'paginationStatus' be an out parameter.")]
        public IEnumerable<UpdateDto> BuildActivityFeed(out PaginationStatus paginationStatus)
        {
            Contract.Requires<NullReferenceException>(this.UserGroups != null);
            Contract.Requires<NullReferenceException>(this.TopicsFilter != null);

            var updates = this.SecurityTrimUpdates(this.FilterUpdates(this.GetUpdates()));

            var currentPageUpdates = this.PaginateUpdates(updates, out paginationStatus);

            return this.UpdateDtoBuilder.BuildUpdateDtos(currentPageUpdates).ToList();
        }

        private IQueryable<Update> GetUpdates()
        {
            IQueryable<Update> updates;
            if (String.IsNullOrEmpty(this.SearchTerms))
            {
                updates = this.ActivityFeedService.GetUpdates();
            }
            else
            {
                updates = this.ActivityFeedService.SearchUpdates(this.SearchTerms);
            }
            return updates;
        }

        protected abstract IQueryable<Update> FilterUpdates(IQueryable<Update> updates);

        protected abstract IQueryable<Update> SecurityTrimUpdates(IQueryable<Update> updates);

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters")]
        protected virtual IEnumerable<Update> PaginateUpdates(IQueryable<Update> updates, out PaginationStatus paginationStatus)
        {
            if (this.PaginationRequest == null)
            {
                paginationStatus = PaginationStatus.CompleteResults;
                return updates;
            }

            //
            // Try to get 1 extra update to check if there are more updates
            //            
            var currentPageUpdates = updates.GetPage(this.PaginationRequest.DateFrom, this.PaginationRequest.PageSize + 1).ToList();

            if (currentPageUpdates.Count > this.PaginationRequest.PageSize)
            {
                currentPageUpdates = currentPageUpdates.Take(currentPageUpdates.Count - 1).ToList();
                paginationStatus = PaginationStatus.PartialResults;
            }
            else
            {
                paginationStatus = PaginationStatus.CompleteResults;
            }

            return currentPageUpdates;
        }
    }

    public interface IActivityFeedBuilderFactory
    {
        ActivityFeedBuilder Create(FeedType feedType, string customFeedTypeName, IActivityFeedService activityFeedService,
                                   IUpdateDtoBuilder updateDtoBuilder, string identityName);
    }
}
